﻿#if NETCORE

using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Builder;
using System.Threading.Tasks;
using System.Net;
using System.Net.WebSockets;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.Security.Authentication;
using Microsoft.Extensions.Logging.Console;

namespace Apewer.Web
{

    /// <summary>ASP.NET Core 服务器。</summary>
    public abstract class AspNetCoreServer : IDisposable
    {

        #region 通用。

        IHost _host;
        IHostBuilder _builder;

        private bool _running = false;

        /// <summary>正在运行。</summary>
        public bool Running { get => _running; }

        /// <summary>启动 Host。</summary>
        protected Exception Run<TStartup>(bool async) where TStartup : AspNetCoreStartup
        {
            try
            {
                _builder = Host.CreateDefaultBuilder();

                if (!LogConsole)
                {
                    _builder.ConfigureLogging((context, builder) =>
                    {
                        if (context.HostingEnvironment.IsProduction())
                        {
                            foreach (var sd in builder.Services)
                            {
                                if (sd.ImplementationType.Equals(typeof(ConsoleLoggerProvider)))
                                {
                                    builder.Services.Remove(sd);
                                    break;
                                }
                            }
                        }
                    });
                }
                _builder.ConfigureWebHostDefaults((builder) =>
                {
                    Configure(builder);
                    builder.UseIIS();
                    builder.UseStartup<TStartup>();
                });

                // 运行。
                _host = _builder.Build();
                if (async) _host.RunAsync();
                else _host.Run();

                return null;
            }
            catch (Exception ex)
            {
                return ex;
            }
        }

        /// <summary>配置 WebHost 构建程序。</summary>
        protected abstract void Configure(IWebHostBuilder builder);

        /// <summary>启动。</summary>
        public abstract void Run<T>() where T : AspNetCoreStartup;

        /// <summary>释放非托管资源。</summary>
        public void Dispose()
        {
            RuntimeUtility.Dispose(_host);
            _host = null;
            _running = false;
        }

        #endregion

        #region 用于派生类的属性。

        private int _port = -1;
        private bool _compression = false;
        private long _maxbody = 1073741824L;
        private X509Certificate2 _certificate = null;
        private SslProtocols _ssl = SslProtocols.Tls;

        /// <summary>监听的端口。默认值：自动选择 80 端口或 443 端口。</summary>
        public int Port
        {
            get { return (_port < 0) ? (_certificate == null ? 80 : 443) : _port; }
            set { if (!_running) _port = value.Restrict(0, 65535); }
        }

        /// <summary>使用的证书。默认值：无。</summary>
        public X509Certificate2 Certificate
        {
            get { return _certificate; }
            set { if (!_running) _certificate = value; }
        }

        /// <summary>请求的最大 Body 大小，单位为字节，最小为 1 MB。默认值：1073741824（1 GB）。</summary>
        public long MaxBody
        {
            get { return _maxbody; }
            set { if (!_running) _maxbody = value.Restrict(1048576L, 1073741824L); }
        }

        /// <summary>使用 SSL 时的协议。默认值：TLS 1.0。</summary>
        public SslProtocols SslProtocol
        {
            get { return _ssl; }
            set { if (!_running) _ssl = value; }
        }

        /// <summary>尝试启用压缩。默认值：不启用。</summary>
        public bool Compression
        {
            get { return _compression; }
            set { if (!_running) _compression = value; }
        }

        /// <summary>使用默认的控制台日志。</summary>
        /// <remarks>默认值：TRUE</remarks>
        public bool LogConsole { get; set; } = true;

        #endregion

    }

}

#endif
